/**
 * Copyright (c) 2011 Bing Wei
 */

package edu.ucsb.android.APMap;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;


public class GPSService extends Service {
	private Location myLocation;
	private String wifiInfo = "Detecting...";
	private ServiceBinder serviceBinder = new ServiceBinder();
	
	LocationManager locationManager;
	WifiManager wifiManager;
	Timer locationTimer;
	
	boolean gpsEnabled = false;
	boolean networkEnabled = false;
	
	@Override
    public void onCreate() {
		Log.d("#########", "service started");
		super.onCreate();
		
		locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
       	 
		/*
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setAltitudeRequired(false);
        criteria.setBearingRequired(false);
        criteria.setCostAllowed(true);
        criteria.setPowerRequirement(Criteria.POWER_LOW);
        	 
        String provider = locationManager.getBestProvider(criteria, true);
        Log.d("APMapService", "############ Starting GPS");
        // locationListener.onlocationChanged() is invoked every 1s and the distance is larger than 5m
        locationManager.requestLocationUpdates(provider, 1000, 0, locationListener);
        */
        
        try{
        	gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        	Log.d("GPSService", "########### gps enabled");
        } catch(Exception ex){}
        try{
        	networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        	Log.d("GPSService", "########### network enabled");
        } catch(Exception ex){}

        
        //don't start listeners if no provider is enabled
        if(!gpsEnabled && !networkEnabled){
        	Log.w("GPSService", "############ gsp and network location are not enalbed");
        	return;
        }
            
        if(gpsEnabled)
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 10, locationListenerGps);
        if(networkEnabled)
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, 10, locationListenerNetwork);
        
        locationTimer = new Timer();
        locationTimer.schedule(new LastLocation(), 60000);
	}
	
	private final LocationListener locationListenerGps = new LocationListener() {
		
		public void onLocationChanged(Location location) {
			Log.d("GPSService", "########### on location change througth gps");
			locationTimer.cancel();
			myLocation = location;
			scanApAndSaveToFile();
			
			// TODO save to file or send to server immediately
			
		}
		
		public void onProviderDisabled(String provider) {
		
		}
		
		public void onProviderEnabled(String provider) {
			
		}
		
		public void onStatusChanged(String provider, int status, Bundle extras) {
			
		}
	};
	
private final LocationListener locationListenerNetwork = new LocationListener() {
		
		public void onLocationChanged(Location location) {
			Log.d("GPSService", "########### on location change through network");
			locationTimer.cancel();
			myLocation = location;
			scanApAndSaveToFile();
			
			// TODO save to file or send to server immediately
			
		}
		
		public void onProviderDisabled(String provider) {
		
		}
		
		public void onProviderEnabled(String provider) {
			
		}
		
		public void onStatusChanged(String provider, int status, Bundle extras) {
			
		}
	};
	
	@Override
    public IBinder onBind(Intent intent) {
		return serviceBinder;
    }
	
	/*TODO stop the thread for pushing files to the server*/
	@Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("GPSService", "################# service is destroy");
    }
	
	public class ServiceBinder extends Binder implements IAPMapService{
		@Override
		public Location getGpsLocation() {
			return myLocation;
		}
		
		@Override
		public String getAPInfo() {
			return wifiInfo;
		}

    }
	
	private void scanApAndSaveToFile(){
		FileOP fileOP = FileOP.getFileOP();
		wifiInfo = scanAP();
		fileOP.writeToFile("Beginning_LOC" + "\n" 
				+ myLocation.getLatitude() + "," 
				+ myLocation.getLongitude() + "," 
				+ myLocation.getAltitude() 
				+ "\n" + "Ending_LOC" + "\n" 
				+ "Beginnig_TS" + "\n" + getTimestamp() 
				+ "\n" + "Ending_TS" + "\n"
				+ wifiInfo);
	}
	
	private String scanAP(){
		Log.d("GPSService", "########### scan wifi");
		wifiManager.startScan();
		List<ScanResult> results = wifiManager.getScanResults();
		if(results == null || results.size() ==0)
			return "No AP detected";
		for(ScanResult res : results){
			if(res.capabilities == null || res.capabilities.equals("")){
				res.capabilities = "NO_AUTH";
			}
		}
		StringBuffer wifiInfo = new StringBuffer();
		//wifiInfo.append(results.size() + " APs are detected" + "\n");
		wifiInfo.append("Beginning_APs" + "\n");
		for(ScanResult result : results){
			wifiInfo.append(result.SSID + "," 
					+ result.level + "," 
					+ result.frequency + "," 
					+ result.BSSID + "," 
					+ result.capabilities + "\n");
		}
		wifiInfo.append("Ending_APs" + "\n");
		return wifiInfo.toString();
	}
	
	private long getTimestamp() {
		long timestamp = System.currentTimeMillis()/1000;
		return timestamp;
	}
	
	class LastLocation extends TimerTask {
        @Override
        public void run() {
        	Log.d("GPSService", "########### time out, use previous location");
             locationManager.removeUpdates(locationListenerGps);

             Location netLoc=null, gpsLoc=null;
             if(gpsEnabled)
                 gpsLoc=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
             if(networkEnabled)
                 netLoc=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

             //if there are both values use the latest one
             if(gpsLoc!=null && netLoc!=null){
                 if(gpsLoc.getTime() > netLoc.getTime())
                     myLocation = gpsLoc;
                 else
                     myLocation = netLoc;
                 return;
             }

             if(gpsLoc!=null){
                 myLocation = gpsLoc;
                 return;
             }
             if(netLoc!=null){
                 myLocation = netLoc;
                 return;
             }
        }
    }
	
}